package edu.uis.project.frankszoo.model.deck;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import edu.uis.project.frankszoo.model.card.Card;
import edu.uis.project.frankszoo.model.card.Crocodile;
import edu.uis.project.frankszoo.model.card.Elephant;
import edu.uis.project.frankszoo.model.card.Fish;
import edu.uis.project.frankszoo.model.card.Fox;
import edu.uis.project.frankszoo.model.card.HedgeHog;
import edu.uis.project.frankszoo.model.card.Joker;
import edu.uis.project.frankszoo.model.card.Lion;
import edu.uis.project.frankszoo.model.card.Mosquito;
import edu.uis.project.frankszoo.model.card.Mouse;
import edu.uis.project.frankszoo.model.card.Perch;
import edu.uis.project.frankszoo.model.card.PolarBear;
import edu.uis.project.frankszoo.model.card.Seal;
import edu.uis.project.frankszoo.model.card.Whale;

/**
 * DeckBuilder class represents the card deck for Frank's Zoo game. This class builds individual player's card decks for each hand. It also shuffles
 * and partitions the deck.
 */
public class DeckBuilder {

	protected List<Card> cardDeck;// List of cards in the Frank's Zoo game
	protected int playerCount;// No of players playing the game

	/**
	 * This is the default constructor for the DeckBuilder. It will build an unshuffled deck of 60 cards with a default player count of 4
	 */
	public DeckBuilder() {
		this.playerCount = 4;
		buildUnshuffledDeck();
	}

	/**
	 * This method builds player's deck in the game. It contains a list of all 60 cards in the game
	 */
	private void buildUnshuffledDeck() {
		this.cardDeck = new ArrayList<Card>();

		for (int i = 0; i < Crocodile.maxCardsPerDeck; i++) {
			cardDeck.add(new Crocodile());
		}

		for (int i = 0; i < Elephant.maxCardsPerDeck; i++) {
			cardDeck.add(new Elephant());
		}

		for (int i = 0; i < Fish.maxCardsPerDeck; i++) {
			cardDeck.add(new Fish());
		}
		for (int i = 0; i < Fox.maxCardsPerDeck; i++) {
			cardDeck.add(new Fox());
		}

		for (int i = 0; i < HedgeHog.maxCardsPerDeck; i++) {
			cardDeck.add(new HedgeHog());
		}

		for (int i = 0; i < Lion.maxCardsPerDeck; i++) {
			cardDeck.add(new Lion());
		}

		for (int i = 0; i < Mouse.maxCardsPerDeck; i++) {
			cardDeck.add(new Mouse());
		}

		for (int i = 0; i < Perch.maxCardsPerDeck; i++) {
			cardDeck.add(new Perch());
		}

		for (int i = 0; i < PolarBear.maxCardsPerDeck; i++) {
			cardDeck.add(new PolarBear());
		}

		for (int i = 0; i < Seal.maxCardsPerDeck; i++) {
			cardDeck.add(new Seal());
		}

		for (int i = 0; i < Whale.maxCardsPerDeck; i++) {
			cardDeck.add(new Whale());
		}

		for (int i = 0; i < Mosquito.maxCardsPerDeck; i++) {
			cardDeck.add(new Mosquito());
		}
		for (int i = 0; i < Joker.maxCardsPerDeck; i++) {
			cardDeck.add(new Joker());
		}

	}

	/**
	 * This method shuffles the cards in the deck. We just call shuffle 5 time to create enough randomness
	 */
	private void shuffleDeck() {
		Collections.shuffle(cardDeck);
		Collections.shuffle(cardDeck);
		Collections.shuffle(cardDeck);
		Collections.shuffle(cardDeck);
		Collections.shuffle(cardDeck);
	}

	/**
	 * This method uses the dealerPosition to deal the cards to the players. It will cycle in the player order beginning with the player to the left
	 * of the dealer, this corresponds to the next serial order.
	 * 
	 * @param dealerPlayerPosition
	 *            This indicates the serial position of the dealer. A value from 1 to 4
	 * @returns list of PlayerDeck Player deck of cards
	 * @throws Exception
	 *             if the dealer's position is less than or above the players count
	 */
	public List<PlayerDeck> getPlayerDecks(int dealerPlayerPosition) throws Exception {
		if ((dealerPlayerPosition > playerCount) || (dealerPlayerPosition < 1)) {
			throw new Exception("Invalid dealer position {Must be between 1 and playerCount}");
		}

		shuffleDeck();

		List<PlayerDeck> playerDecks = new ArrayList<PlayerDeck>();
		System.out.println("Dealing cards...");

		// For each of the 4 players. Add a playerDeck
		for (int i = 0; i < playerCount; i++) {
			PlayerDeck playerDeck = new PlayerDeck();
			playerDecks.add(playerDeck);
		}

		// Cycle in the player order beginning with the player in the next serial order to the dealer. Eg:If Player3 is the dealer then the dealing
		// order will be 4-1-2-3-4-3.. until cards run out
		for (int c = 0; c < cardDeck.size(); c++) {
			int dealingIndex = ((c % playerCount) + dealerPlayerPosition) % playerCount;
			playerDecks.get(dealingIndex).deckInHand.add(cardDeck.get(c));
		}
		return playerDecks;
	}

}
